package io.gitee.yxsnake.tenant.datasource.configuration;

import com.alibaba.druid.spring.boot3.autoconfigure.DruidDataSourceBuilder;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.*;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import io.gitee.yxsnake.tenant.datasource.CustomDynamicDataSource;
import io.gitee.yxsnake.tenant.datasource.configuration.properties.MybatisPlusExtProperties;
import io.gitee.yxsnake.tenant.datasource.constant.DynamicDatasourceConstant;
import io.gitee.yxsnake.tenant.datasource.handler.CustomTenantHandler;
import io.gitee.yxsnake.tenant.datasource.handler.MybatisExceptionHandler;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author: snake
 * @create-time: 2024-10-10
 * @description:
 * @version: 1.0
 */
@Slf4j
@Import({MybatisPlusExtProperties.class,})
@Configuration
@RequiredArgsConstructor
public class CustomMybatisPlusAutoConfiguration {


    private final MybatisPlusExtProperties mybatisPlusExtProperties;
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 添加非法SQL拦截器
        if(mybatisPlusExtProperties.getIllegalEnabled()){
            interceptor.addInnerInterceptor(new IllegalSQLInnerInterceptor());
        }

        if(mybatisPlusExtProperties.getTenantEnabled()){
            TenantLineInnerInterceptor tenantInterceptor = new TenantLineInnerInterceptor();
            tenantInterceptor.setTenantLineHandler(customTenantHandler());
            interceptor.addInnerInterceptor(tenantInterceptor);
        }
        // 配置分页插件
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        // 防全表更新删除操作
        if(mybatisPlusExtProperties.getBlockAttackEnabled()){
            interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
        }
        // 增加@Version乐观锁支持
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }


    /**
     * 异常处理器
     */
    @Bean
    public MybatisExceptionHandler mybatisExceptionHandler() {
        return new MybatisExceptionHandler();
    }

    /**
     * 配置事务
     * @param dynamicDataSource
     * @return
     */
    @Bean
    @Qualifier("transactionManager")
    public PlatformTransactionManager txManager(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
        return new DataSourceTransactionManager(dynamicDataSource);
    }

    /**
     * 配置文件yml中的默认数据源
     * @return
     */
    @Bean(name = "defaultDataSource")
    @ConfigurationProperties(prefix="spring.datasource")
    public DataSource getDefaultDataSource() {
        return DruidDataSourceBuilder.create().build();
    }

    /**
     * 将动态数据源对象放入spring中管理
     * @return
     */
    @Bean
    public CustomDynamicDataSource dynamicDataSource() {

        Map<Object, Object> targetDataSources = new HashMap<>();
        log.info("将druid数据源放入默认动态数据源对象中");
        targetDataSources.put(DynamicDatasourceConstant.TENANT_CONFIG_KEY, getDefaultDataSource());
        return new CustomDynamicDataSource(getDefaultDataSource(), targetDataSources);
    }

    /**
     * 数据库连接会话工厂
     * @param dynamicDataSource 自定义动态数据源
     * @return
     * @throws Exception
     */
    @Bean
    public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dynamicDataSource);
        bean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath*:mapper/**/*.xml"));
        return bean.getObject();
    }

    @Bean
    public GlobalConfig getGlobalConfig() {
        GlobalConfig globalConfig = new GlobalConfig();
        GlobalConfig.DbConfig dbConfig = new GlobalConfig.DbConfig();
        //已删除
        dbConfig.setLogicDeleteValue("0");
        //未删除
        dbConfig.setLogicNotDeleteValue("1");
        dbConfig.setLogicDeleteField("active");
        globalConfig.setDbConfig(dbConfig);
        return globalConfig;
    }

    @Bean
    public SqlSessionTemplate sqlSessionTemplate(@Qualifier("sqlSessionFactory") SqlSessionFactory sqlSessionFactory){
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    public CustomTenantHandler customTenantHandler(){
        return new CustomTenantHandler(mybatisPlusExtProperties);
    }
}
